﻿//=============================================================================
// System  : Sandcastle Help File Builder Plug-Ins
// File    : AdditionalContentOnlyPlugIn.cs
// Author  : Eric Woodruff  (Eric@EWoodruff.us)
// Updated : 10/09/2008
// Note    : Copyright 2007-2008, Eric Woodruff, All rights reserved
// Compiler: Microsoft Visual C#
//
// This file contains a plug-in that can be used to build a help file
// consisting of nothing but additional content items.  It is also useful for
// proofreading your additional content without having to build all the API
// topics.
//
// This code is published under the Microsoft Public License (Ms-PL).  A copy
// of the license should be distributed with the code.  It can also be found
// at the project website: http://SHFB.CodePlex.com.   This notice, the
// author's name, and all copyright notices must remain intact in all
// applications, documentation, and source files.
//
// Version     Date     Who  Comments
// ============================================================================
// 1.5.2.0  09/13/2007  EFW  Created the code
// 1.6.0.7  05/27/2008  EFW  Modified to support use in conceptual preview
// 1.8.0.0  08/05/2008  EFW  Modified to support the new project format
//=============================================================================

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Linq;
using System.Collections.Generic;
using System.Collections;

using SandcastleBuilder.Utils;
using SandcastleBuilder.Utils.BuildEngine;
using SandcastleBuilder.Utils.PlugIn;

namespace SandcastleBuilder.PlugIns
{
    /// <summary>
    /// This plug-in class can be used to build a help file consisting of
    /// nothing but additional content items.  It is also useful for
    /// proofreading your additional content without having to build all the
    /// API topics.
    /// </summary>
    public class Docx_BuilderPlugInPlugIn : IPlugIn
    {
        #region Private data members
        private ExecutionPointCollection executionPoints;

        private BuildProcess builder;

        private string outputPath;
        private string basePath;
        private string docxName;
        private string styleName = "simple";
        private string shfbFolder;
        private string pathContentLayout;
        private List<string> tokenFiles;

        private bool isTokenFile = false;

        private string isContent = "false";
        private string isPDF = "false";
        private string isXPS = "false";

        #endregion

        #region IPlugIn implementation
        //=====================================================================
        // IPlugIn implementation

        /// <summary>
        /// This read-only property returns a friendly name for the plug-in
        /// </summary>
        public string Name
        {
            get { return "Docx Builder"; }
        }

        /// <summary>
        /// This read-only property returns the version of the plug-in
        /// </summary>
        public Version Version
        {
            get
            {
                // Use the assembly version
                Assembly asm = Assembly.GetExecutingAssembly();
                FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(
                    asm.Location);

                return new Version(fvi.ProductVersion);
            }
        }

        /// <summary>
        /// This read-only property returns the copyright information for the
        /// plug-in.
        /// </summary>
        public string Copyright
        {
            get
            {
                // Use the assembly copyright
                Assembly asm = Assembly.GetExecutingAssembly();
                AssemblyCopyrightAttribute copyright =
                    (AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(
                        asm, typeof(AssemblyCopyrightAttribute));

                return copyright.Copyright + "\r\nDocx_Builder is Copyright \xA9 " +
                    "2006-2007 Pavlov Alexandr, All Rights Reserved";
            }
        }

        /// <summary>
        /// This read-only property returns a brief description of the plug-in
        /// </summary>
        public string Description
        {
            get
            {
                return "Creation to documentation in format docx";
            }
        }

        /// <summary>
        /// This plug-in does not run in partial builds
        /// </summary>
        public bool RunsInPartialBuild
        {
            get { return false; }
        }

        /// <summary>
        /// This read-only property returns a collection of execution points
        /// that define when the plug-in should be invoked during the build
        /// process.
        /// </summary>
        public ExecutionPointCollection ExecutionPoints
        {
            get
            {
                if (executionPoints == null)
                {
                    executionPoints = new ExecutionPointCollection();
                    executionPoints.Add(new ExecutionPoint(
                        BuildStep.MergeCustomConfigs,
                        ExecutionBehaviors.After));
                }

                return executionPoints;
            }
        }

        /// <summary>
        /// This method is used by the Sandcastle Help File Builder to let the
        /// plug-in perform its own configuration.
        /// </summary>
        /// <param name="project">A reference to the active project</param>
        /// <param name="currentConfig">The current configuration XML fragment</param>
        /// <returns>A string containing the new configuration XML fragment</returns>
        /// <remarks>The configuration data will be stored in the help file
        /// builder project.</remarks>
        public string ConfigurePlugIn(SandcastleProject project,
          string currentConfig)
        {
            using (Docx_BuilderConfigDlg dlg = new Docx_BuilderConfigDlg(currentConfig))
            {
                if (dlg.ShowDialog() == DialogResult.OK)
                    currentConfig = dlg.Configuration;
            }

            return currentConfig;
        }

        /// <summary>
        /// This method is used to initialize the plug-in at the start of the
        /// build process.
        /// </summary>
        /// <param name="buildProcess">A reference to the current build
        /// process.</param>
        /// <param name="configuration">The configuration data that the plug-in
        /// should use to initialize itself.</param>
        public void Initialize(BuildProcess buildProcess,
          XPathNavigator configuration)
        {
            XPathNavigator root, node;

            builder = buildProcess;

            shfbFolder = builder.HelpFileBuilderFolder;
            outputPath = builder.OutputFolder;
            basePath = builder.CurrentProject.BasePath;
            docxName = builder.CurrentProject.HtmlHelpName;

            if (File.Exists(outputPath + "\\" + docxName + ".docx"))
                File.Delete(outputPath + "\\" + docxName + ".docx");

            System.Collections.ObjectModel.Collection<FileItem> fileItems = builder.CurrentProject.FileItems;

            if (builder.CurrentProject.HasItems(BuildAction.Tokens))
            {
                isTokenFile = true;
                tokenFiles = new List<string>();
                foreach (FileItem file in fileItems)
                {
                    if (file.BuildAction == BuildAction.Tokens)
                        tokenFiles.Add(file.Name);
                    if(file.BuildAction == BuildAction.ContentLayout)
                        pathContentLayout = file.FullPath;
                }
            }

            if (builder.CurrentProject.HasItems(BuildAction.ContentLayout))
            {
                foreach (FileItem file in fileItems)
                {
                    if (file.BuildAction == BuildAction.ContentLayout)
                        pathContentLayout = file.FullPath;
                }
            }

            builder.ReportProgress("{0} Version {1}\r\n{2}",
                this.Name, this.Version, this.Copyright);

            root = configuration.SelectSingleNode("configuration");

            if (!root.IsEmptyElement)
            {
                node = root.SelectSingleNode("elementsDoc");
                if (node != null)
                {
                    isContent = node.GetAttribute("content", String.Empty).Trim();
                }

                node = root.SelectSingleNode("convert");
                if (node != null)
                {
                    isPDF = node.GetAttribute("PDF", String.Empty).Trim();
                    isXPS = node.GetAttribute("XPS", String.Empty).Trim();
                }

                node = root.SelectSingleNode("style");
                if (node != null)
                    styleName = node.GetAttribute("name", String.Empty).Trim();
            }
        }

        /// <summary>
        /// This method is used to execute the plug-in during the build process
        /// </summary>
        /// <param name="context">The current execution context</param>
        public void Execute(ExecutionContext context)
        {
            if (context.BuildStep == BuildStep.MergeCustomConfigs &&
              builder.CurrentProject.HasItems(BuildAction.ContentLayout))
            {
                XDocument doc = XDocument.Load(builder.WorkingFolder + "conceptual.config");

                XElement component = new XElement("component");
                XAttribute type = new XAttribute("type", "component.DocxBuilderComponent");
                XAttribute assembly = new XAttribute("assembly", shfbFolder+"DocxBuilderComponent.dll");
                component.Add(type);
                component.Add(assembly);

                XElement documentation = new XElement("documentation");
                XAttribute nameDoc = new XAttribute("name", docxName);
                documentation.Add(nameDoc);
                component.Add(documentation);

                XElement path = new XElement("path");
                XAttribute oPath = new XAttribute("outputPath", outputPath);
                XAttribute bPath = new XAttribute("basePath", basePath);
                path.Add(oPath);
                path.Add(bPath);
                component.Add(path);

                if (isTokenFile)
                {
                    foreach (string nameFile in tokenFiles)
                    {
                        XElement tokenFile = new XElement("tokenFile");
                        XAttribute file = new XAttribute("file", nameFile);
                        tokenFile.Add(file);
                        component.Add(tokenFile);
                    }
                }

                XElement data = new XElement("data");
                XAttribute files = new XAttribute("files", @"xmlcomp\*.xml");
                data.Add(files);
                component.Add(data);

                XElement contentLayout = new XElement("contentLayout");
                XAttribute fileContent = new XAttribute("file", pathContentLayout);
                contentLayout.Add(fileContent);
                component.Add(contentLayout);

                XElement elementsDoc = new XElement("elementsDoc");
                XAttribute attrContent = new XAttribute("content", isContent);
                elementsDoc.Add(attrContent);
                component.Add(elementsDoc);

                XElement convert = new XElement("convert");
                XAttribute attrPDF = new XAttribute("PDF", isPDF);
                XAttribute attrXPS = new XAttribute("XPS", isXPS);
                convert.Add(attrPDF);
                convert.Add(attrXPS);
                component.Add(convert);

                XElement style = new XElement("style");
                XAttribute name = new XAttribute("name", styleName);
                style.Add(name);
                component.Add(style);

                XElement root = doc.Root;
                XElement dduetools = root.Element("dduetools");
                XElement b = dduetools.Element("builder");
                XElement components = b.Element("components");

                IEnumerable<XElement> elements =
                    from el in components.Elements("component")
                    select el;
                int i = 0;
                foreach (XElement el in elements)
                {
                    if (i == 1)
                    {
                        el.AddAfterSelf(component);
                        break;
                    }
                    i++;
                }

                doc.Save(builder.WorkingFolder + "conceptual.config");
            }
        }
        #endregion

        #region IDisposable implementation
        //=====================================================================
        // IDisposable implementation

        /// <summary>
        /// This handles garbage collection to ensure proper disposal of the
        /// plug-in if not done explicity with <see cref="Dispose()"/>.
        /// </summary>
        ~Docx_BuilderPlugInPlugIn()
        {
            this.Dispose(false);
        }

        /// <summary>
        /// This implements the Dispose() interface to properly dispose of
        /// the plug-in object.
        /// </summary>
        /// <overloads>There are two overloads for this method.</overloads>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// This can be overridden by derived classes to add their own
        /// disposal code if necessary.
        /// </summary>
        /// <param name="disposing">Pass true to dispose of the managed
        /// and unmanaged resources or false to just dispose of the
        /// unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            // Nothing to dispose of in this one
        }
        #endregion
    }
}
